package com.jshan.blog.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jshan.blog.base.admin.dto.MenuListDto;
import com.jshan.blog.base.admin.entity.SysMenu;
import com.jshan.blog.base.admin.entity.SysRoleDict;
import com.jshan.blog.base.admin.entity.SysRoleMenu;
import com.jshan.blog.base.admin.entity.SysUser;
import com.jshan.blog.converts.SysMenuConvert;
import com.jshan.blog.mapper.SysMenuMapper;
import com.jshan.blog.service.SysMenuService;
import com.jshan.blog.service.SysRoleDictService;
import com.jshan.blog.service.SysRoleMenuService;
import com.jshan.blog.service.SysUserService;
import com.jshan.blog.utils.RedisUtil;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.jshan.blog.constans.RedisAllKeyConst.ALL_MENU_KEY;
import static com.jshan.blog.constans.RedisAllKeyConst.ONE_MENU_KEY;


/**
 * @author jshan
 * @description 针对表【sys_menu】的数据库操作Service实现
 * @createDate 2025-01-20 16:42:14
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>
        implements SysMenuService {

    @Resource
    private SysRoleMenuService roleMenuService;
    @Resource
    private SysUserService userService;
    @Resource
    private SysRoleDictService roleDictService;

    @Resource
    private RedisUtil redisUtil;


    /**
     * 获取菜单数据
     *
     * @param type 类型，one为启动的菜单， all为所有的菜单
     * @return List<MenuListDto> 返回组装好的菜单数据 通过递归组装
     */
    @Override
    public List<MenuListDto> findMenuAll(String type) {
        List<SysMenu> list = new ArrayList<>();
        if (StringUtils.isNotBlank(type)) {
            if ("one".equals(type)) {
                // String oneMenuStr = redisUtil.getValue(ONE_MENU_KEY + StpUtil.getLoginId());
                String oneMenuStr = "";
                if (StringUtils.isBlank(oneMenuStr)) {
                    LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getIsStatus, 0).and(r -> r.ne(SysMenu::getMenuTypeCd, "按钮"));
                    List<Integer> ids = new ArrayList<>();
                    SysUser user = userService.getById(StpUtil.getLoginIdAsInt());
                    SysRoleDict roleDict = roleDictService.getOne(new LambdaQueryWrapper<SysRoleDict>().eq(SysRoleDict::getTagId, user.getUserTagCd()));
                    // 通过role_id 查询出role-->menu对应关系 找到对应的menu[]
                    SysRoleMenu roleMenu = roleMenuService.getOne(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleDict.getRoleId()));
                    if (StringUtils.isNotBlank(roleMenu.getMenuId())) {
                        String[] menus = roleMenu.getMenuId().split(",");
                        for (String menu : menus) {
                            ids.add(Integer.parseInt(menu));
                        }
                    }
                    wrapper.in(SysMenu::getId, ids);
                    list = this.list(wrapper);
                    // redisUtil.setValue(ONE_MENU_KEY + StpUtil.getLoginId(), JSON.toJSONString(list));
                    // redisUtil.push(ONE_MENU_KEY, StpUtil.getLoginIdAsInt());
                } else {
                    // 使用 fastjson2 将 JSON 字符串解析为 List<SysMenu>
                    list = JSON.parseObject(oneMenuStr, new TypeReference<List<SysMenu>>() {
                    });

                }
            } else if ("all".equals(type)) {
                String allMenuStr = redisUtil.getValue(ALL_MENU_KEY);
                if (StringUtils.isBlank(allMenuStr)) {
                    list = this.list();
                    redisUtil.setValue(ALL_MENU_KEY, JSON.toJSONString(list));
                } else {
                    list = JSON.parseObject(allMenuStr, new TypeReference<List<SysMenu>>() {
                    });
                }
            }
        }
        List<MenuListDto> menuListDtoList = SysMenuConvert.INSTANCE.SysMenuListConvertDtoList(list);

        // 对查出来的菜单进行组合 利用递归去查询
        List<MenuListDto> resultList = menuListDtoList.stream().filter(item -> item.getPid() == 0).map((menu) -> {
            menu.setChildren(getChildren(menu, menuListDtoList));
            return menu;
        }).sorted((menu1, menu2) ->
                (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort()) // 排序
        ).collect(Collectors.toList()); // 收集成 List
        return resultList;
    }

    /**
     * 更新菜单
     *
     * @param menuListDto 接收的菜单数据
     */
    @Override
    public void updateMenuInfo(MenuListDto menuListDto) {
        try {
            SysMenu sysMenu = SysMenuConvert.INSTANCE.MenuDtoConvertSysMenu(menuListDto);
            sysMenu.setUpdateId(StpUtil.getLoginIdAsInt());
            sysMenu.setUpdateTime(LocalDateTime.now());
            this.updateById(sysMenu);
            // redisUtil.deleteAll(ONE_MENU_KEY, ALL_MENU_KEY);
            redisUtil.deleteValue(ONE_MENU_KEY);
            redisUtil.deleteValue(ALL_MENU_KEY);
        } catch (Exception e) {
            new Throwable(e.getMessage());
        }
    }

    /**
     * 获取所有父级菜单数据
     *
     * @return 返回需要的数据
     */
    @Override
    public List<Map<Integer, String>> getPartMenuList() {
        return baseMapper.getPartMenuList();
    }

    /**
     * 新增菜单
     *
     * @param menuListDto 传递的菜单需要的数据
     * @return 返回结果true or false
     */
    @Override
    public Boolean saveMenuInfo(MenuListDto menuListDto) {
        SysMenu sysMenu = SysMenuConvert.INSTANCE.MenuDtoConvertSysMenu(menuListDto);
        sysMenu.setCreateId(StpUtil.getLoginIdAsInt());
        sysMenu.setCreateTime(LocalDateTime.now());
        Boolean flag = this.save(sysMenu);
        // redisUtil.deleteAll(ONE_MENU_KEY, ALL_MENU_KEY);
        redisUtil.deleteValue(ONE_MENU_KEY);
        redisUtil.deleteValue(ALL_MENU_KEY);
        return flag;
    }

    /**
     * 获取所有的menuId
     *
     * @param roleId 角色id
     * @return 返回组装好的menuId
     */
    @Override
    public List<Integer> getIds(Integer roleId) {
        List<Integer> ids = new ArrayList<>();
        // 1.前端传递过来roleId
        SysRoleMenu roleMenu = roleMenuService.getOne(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getRoleId, roleId));
        if (ObjectUtils.isNotEmpty(roleMenu) && ObjectUtils.isNotEmpty(roleMenu.getMenuId())) {
            String[] menuIds = roleMenu.getMenuId().split(",");
            for (String menuId : menuIds) {
                ids.add(Integer.parseInt(menuId));
            }
        }
        return ids;
    }

    @Override
    public Set<String> getPermAll() {
        return baseMapper.getPermAll();
    }

    @Override
    public Set<String> getBatchIds(Set<Integer> menuIds) {
        return baseMapper.getBatchIds(menuIds);
    }

    /**
     * 递归组装菜单信息
     *
     * @param menu            菜单数据
     * @param menuListDtoList 组装数据
     * @return List<MenuListDto>
     */
    private List<MenuListDto> getChildren(MenuListDto menu, List<MenuListDto> menuListDtoList) {
        List<MenuListDto> childrenList = menuListDtoList.stream().filter(item ->
                menu.getId() == item.getPid()
        ).map((root) -> {
            root.setChildren(getChildren(root, menuListDtoList));
            return root;
        }).sorted((menu1, menu2) -> {
            return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
        }).collect(Collectors.toList());
        return childrenList;
    }
}




